﻿using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;
using TK_CSLua.ILAnalyze;

namespace CSLua
{
	// Token: 0x0200000F RID: 15
	public abstract class MethodGenerator : MethodBodyPhase
	{
		// Token: 0x06000066 RID: 102 RVA: 0x000040FC File Offset: 0x000022FC
		public override ILBlock getBlock()
		{
			return this.luaMethod.ILMethodBlock;
		}

		// Token: 0x06000067 RID: 103 RVA: 0x00004109 File Offset: 0x00002309
		public override ILNode getParentNode(ILNode node)
		{
			return this.luaMethod.GetParent(node);
		}

		// Token: 0x17000013 RID: 19
		// (get) Token: 0x06000068 RID: 104 RVA: 0x00004117 File Offset: 0x00002317
		public override MethodDefinition Method
		{
			get
			{
				return this.luaMethod.ILMethod;
			}
		}

		// Token: 0x06000069 RID: 105 RVA: 0x00004124 File Offset: 0x00002324
		public MethodGenerator(BuildFilePhase phaseContext, LuaMethod luaMethod) : base(phaseContext)
		{
			this.luaMethod = luaMethod;
		}

		// Token: 0x0600006A RID: 106 RVA: 0x00004134 File Offset: 0x00002334
		protected virtual void writeBodySelf(CodeWriter write)
		{
		}

		// Token: 0x0600006B RID: 107 RVA: 0x00004138 File Offset: 0x00002338
		public void GenerateBody()
		{
			if (BuildConfig.commontILAst)
			{
				this.writer.comment(BuilderUtils.ToString(this.luaMethod.ILMethodBlock)).nextLine();
			}
			if (!this.luaMethod.ILMethod.IsStatic)
			{
				this.writeBodySelf(this.writer);
			}
			if (this.luaMethod.IsIEnumerator)
			{
				this.writer.code("return " + this.buildContext.getCSLLibs(CSLLibs.TKWrapEnumerator) + "(").beginLambda().shiftRightNewLine();
			}
			foreach (LuaMethodSegment luaSegment in this.luaMethod.LuaSegments)
			{
				this.generateMethodSegment(luaSegment);
			}
			if (this.luaMethod.IsIEnumerator)
			{
				this.writer.shiftLeftNewLine(delegate()
				{
					this.writer.endLambda().code(")");
				});
			}
		}

		// Token: 0x0600006C RID: 108 RVA: 0x00004238 File Offset: 0x00002438
		private void generateMethodSegment(LuaMethodSegment luaSegment)
		{
			if (luaSegment.ilSegment is ILExpression)
			{
				// 判断是不是要新建本地变量
				if (luaSegment.newLocalValues.Count == 1)
				{
					this.writer.code(this.writer.tokens.local + " ");
				}
				// 生成方法片段
				this.generateSegment(luaSegment.ilSegment);
				return;
			}
			foreach (string localValue in luaSegment.newLocalValues)
			{
				this.writer.defineLocalValue(localValue, null);
			}
			this.generateSegment(luaSegment.ilSegment);
		}

		// Token: 0x0600006D RID: 109 RVA: 0x000042EC File Offset: 0x000024EC
		private void generateSegment(ILNode node)
		{
            switch (node)
            {
				case ILBlock block:
					generateNode(block);
					break;
				case ILBasicBlock basicBlock:
					generateNode(basicBlock);
					break;
				case ILTryCatchBlock catchBlock:
					generateNode(catchBlock);
					break;
				case ILExpression expression:
					tryGenerateComman(expression);
					ExpressionBuilder.Build(this,expression);
					break;
				case ILWhileLoop whileLoop:
					generateNode(whileLoop);
					break;
				case ILCondition cond:
					generateNode(cond);
					break;
				case ILSwitch sw:
					generateNode(sw);
					break;
				default:
					writer.reportExpressionNotsupport(this, node, node);
					break;
			}
/*
			if (node is ILBlock)
			{
				this.generateNode(node as ILBlock);
				return;
			}
			if (node is ILBasicBlock)
			{
				this.generateNode(node as ILBasicBlock);
				return;
			}
			if (node is ILTryCatchBlock)
			{
				this.generateNode(node as ILTryCatchBlock);
				return;
			}
			if (node is ILExpression)
			{
				ILExpression exp = node as ILExpression;
				this.tryGenerateComman(exp);
				ExpressionBuilder.Build(this, exp);
				return;
			}
			if (node is ILWhileLoop)
			{
				this.generateNode(node as ILWhileLoop);
				return;
			}
			if (node is ILCondition)
			{
				this.generateNode(node as ILCondition);
				return;
			}
			if (node is ILSwitch)
			{
				this.generateNode(node as ILSwitch);
				return;
			}
			this.writer.reportExpressionNotsupport(this, node, node);*/
		}

		// Token: 0x0600006E RID: 110 RVA: 0x000043A4 File Offset: 0x000025A4
		private void tryGenerateComman(ILExpression exp)
		{
			var startLine = getExpressionStartLine(exp);
			//this.writer.commentLine("start line:"+ startLine);
			List<string> comment = this.luaMethod.getExpressionComment(exp);
			if (comment != null)
			{
				foreach (string c in comment)
				{
					this.writer.commentLine(c);
				}
			}
		}

		// Token: 0x0600006F RID: 111 RVA: 0x00004408 File Offset: 0x00002608
		protected void generateNode(ILBlock block)
		{
			BuildFilePhase.Assert(block.EntryGoto == null, null);
			foreach (ILNode node in block.Body)
			{
				this.generateSegment(node);
			}
		}

		// Token: 0x06000070 RID: 112 RVA: 0x0000446C File Offset: 0x0000266C
		private void generateNode(ILBasicBlock block)
		{
			foreach (ILNode node in block.Body)
			{
				this.generateSegment(node);
			}
		}

		// Token: 0x06000071 RID: 113 RVA: 0x000044C0 File Offset: 0x000026C0
		private void generateNode(ILTryCatchBlock block)
		{
			this.generateNode(block.TryBlock);
		}

		// Token: 0x06000072 RID: 114 RVA: 0x000044D0 File Offset: 0x000026D0
		private ILVariable tryGetMoveNextVariable(ILExpression exp, HashSet<ILExpression> iterVarExpSet)
		{
			if (exp != null && (exp.Code == ILCode.Call || exp.Code == ILCode.Callvirt))
			{
				MethodReference method = (MethodReference)exp.Operand;
				if (method.Name == "MoveNext" && MethodGenerator.supportCollectionsEnumerator.Contains(BuilderUtils.GetTypeFullname(method.DeclaringType.Resolve(), true)))
				{
					ILExpression var = exp.Arguments.First<ILExpression>();
					if (var.Code == ILCode.Ldloca || var.Code == ILCode.Ldloc)
					{
						iterVarExpSet.Add(var);
						return var.Operand as ILVariable;
					}
				}
			}
			return null;
		}

		// Token: 0x06000073 RID: 115 RVA: 0x00004570 File Offset: 0x00002770
		private ILVariable tryGetCurrentVariable(ILVariable iterVar, ILExpression exp, HashSet<ILExpression> iterVarExpSet)
		{
			if (exp == null)
			{
				return null;
			}
			if (exp.Code == ILCode.Stloc)
			{
				ILExpression arg = exp.Arguments[0];
				if (arg.Code == ILCode.CallGetter || arg.Code == ILCode.CallvirtGetter)
				{
					ILExpression iterVarExp = arg.Arguments[0];
					if (arg.Arguments.Count > 0 && iterVarExp.Operand == iterVar)
					{
						iterVarExpSet.Add(iterVarExp);
						MethodReference getter = (MethodReference)arg.Operand;
						if (getter.Name == "get_Current" && MethodGenerator.supportCollectionsEnumerator.Contains(BuilderUtils.GetTypeFullname(getter.DeclaringType.Resolve(), true)))
						{
							return (ILVariable)exp.Operand;
						}
					}
				}
			}
			return null;
		}

		// Token: 0x06000074 RID: 116 RVA: 0x00004630 File Offset: 0x00002830
		private bool tryGenerateForeach(ILWhileLoop loop)
		{
			if (loop.BodyBlock.Body.Count == 0)
			{
				return false;
			}
			HashSet<ILExpression> iterVarExpSet = new HashSet<ILExpression>();
			ILVariable iterVar = this.tryGetMoveNextVariable(loop.Condition, iterVarExpSet);
			if (iterVar == null)
			{
				return false;
			}
			ILExpression currentExpression = loop.BodyBlock.Body.First<ILNode>() as ILExpression;
			ILVariable currVar = this.tryGetCurrentVariable(iterVar, currentExpression, iterVarExpSet);
			if (currVar == null)
			{
				return false;
			}
			string iterType = BuilderUtils.GetTypeFullname(iterVar.Type.Resolve(), true);
			if (!MethodGenerator.supportCollectionsEnumerator.Contains(iterType))
			{
				return false;
			}
			if (loop.GetSelfAndChildrenRecursive<ILExpression>((ILExpression exp) => exp.Operand == iterVar && !iterVarExpSet.Contains(exp)).Any<ILExpression>())
			{
				return false;
			}
			loop.BodyBlock.Body.RemoveAt(0);
			this.writeForeach(loop, currVar, iterVar);
			return true;
		}

		// Token: 0x06000075 RID: 117
		protected abstract void writeForeach(ILWhileLoop loop, ILVariable currVar, ILVariable iterVar);

		// Token: 0x06000076 RID: 118 RVA: 0x00004714 File Offset: 0x00002914
		private bool isVariableEquals(ILVariable v1, ILVariable v2)
		{
			return v1 != null && v2 != null && v1.ToString() == v2.ToString();
		}

		// Token: 0x06000077 RID: 119 RVA: 0x0000472F File Offset: 0x0000292F
		private void generateNode(ILWhileLoop loop)
		{
			if (this.tryGenerateForeach(loop))
			{
				return;
			}
			if (BuildConfig.commentILExpression && loop.Condition != null)
			{
				this.writer.commentLine(loop.Condition.ToString());
			}
			this.writeWhileLoop(loop);
		}

		// Token: 0x06000078 RID: 120
		protected abstract void writeWhileLoop(ILWhileLoop loop);

		// Token: 0x06000079 RID: 121 RVA: 0x00004768 File Offset: 0x00002968
		private void generateNode(ILCondition segment)
		{
			if (BuildConfig.commentILExpression)
			{
				this.writer.commentLine(segment.Condition.ToString());
			}
			this.writeCondition(segment);
		}

		// Token: 0x0600007A RID: 122
		protected abstract void writeCondition(ILCondition segment);

		// Token: 0x0600007B RID: 123 RVA: 0x0000478F File Offset: 0x0000298F
		private void generateNode(ILSwitch segment)
		{
			this.writer.reportExpressionNotsupport(this, segment, segment);
		}

		// Token: 0x0600007C RID: 124 RVA: 0x0000479F File Offset: 0x0000299F
		private string getLocalValueName(ILExpression exp)
		{
			return this.luaMethod.getLocalValueName(exp);
		}

		// Token: 0x0600007D RID: 125 RVA: 0x000047AD File Offset: 0x000029AD
		public override string getNamedLocalValue(ILExpression expression)
		{
			return this.getLocalValueName(expression);
		}

		// Token: 0x0600007E RID: 126 RVA: 0x000047B6 File Offset: 0x000029B6
		public override int getNamedLocalValueIndex(ILExpression expression)
		{
			return this.luaMethod.getLocalValueIndex(expression);
		}

		// Token: 0x0600007F RID: 127 RVA: 0x000047C4 File Offset: 0x000029C4
		public override int getExpressionStartLine(ILNode expression)
		{
			return this.luaMethod.getExpressionStartLine(expression);
		}

		// Token: 0x06000080 RID: 128 RVA: 0x000047D2 File Offset: 0x000029D2
		public override string getSrcFile()
		{
			SrcFileCache srcFile = this.luaMethod.SrcFile;
			if (srcFile == null)
			{
				return null;
			}
			return srcFile.getFileName();
		}

		// Token: 0x0400002F RID: 47
		public const string key_suffix = "__key";

		// Token: 0x04000030 RID: 48
		public const string val_suffix = "__val";

		// Token: 0x04000031 RID: 49
		public const string IterMoveNext = "MoveNext";

		// Token: 0x04000032 RID: 50
		public const string IterCurrentGetter = "get_Current";

		// Token: 0x04000033 RID: 51
		public static HashSet<string> supportCollectionsEnumerator = new HashSet<string>
		{
			"System.Collections.Generic.List.Enumerator",
			"System.Collections.IEnumerator",
			"System.Collections.Generic.IEnumerator",
			"System.Collections.Generic.HashSet.Enumerator",
			"System.Collections.Generic.Dictionary.Enumerator",
			"System.Collections.Generic.Dictionary.KeyCollection.Enumerator",
			"System.Collections.Generic.Dictionary.ValueCollection.Enumerator"
		};

		// Token: 0x04000034 RID: 52
		protected LuaMethod luaMethod;
	}
}
